package org.zn.note.jdk.java8.Java8InAction;

import org.zn.note.jdk.java8.Java8InAction.bean.Apple;
import org.zn.note.jdk.java8.Java8InAction.bean.Banana;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

/**
 * 第2章 通过行为参数化传递代码
 */
class Ch2 {

    // 1、筛选绿苹果
    private static List<Apple> filterGreenApples(List<Apple> inventory) {
        String filterColor = "green";
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if (filterColor.equals(apple.getColor())) {
                result.add(apple);
            }
        }
        return result;
    }

    // 2、如果筛选红苹果、黄苹果呢？ --- 将颜色抽象，作为参数传入
    private static List<Apple> filterApplesByColor(List<Apple> inventory, String filterColor) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if (filterColor.equals(apple.getColor())) {
                result.add(apple);
            }
        }
        return result;
    }

    // 3、如果根据重量筛选呢？  --- copy一份上面的代码，然后将颜色改成重量
    private static List<Apple> filterApplesByWeight(List<Apple> inventory, int weight) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory) {
            if (apple.getWeight() > weight) {
                result.add(apple);
            }
        }
        return result;
    }

    // 4、行为参数化
    // 把filter的不同行为看做不同的标准，封装起来(策略)
    // 算法簇是ApplePredicate，不同的策略是 AppleHeavyWeightPredicate & AppleGreenColorPredicate
    // 在filterApples时，接受算法簇ApplePredicate，用其来筛选苹果
    // 行为参数化：让方法接受多种行为(策略)作为参数，并在方法内部使用，使得该方法完成不同的行为。

    // predicate 谓词 （一个返回boolean的函数）
    // 一种更高的抽象，对选择标准建模：根据苹果的一些属性是否满足标准，进而返回boolean
    interface ApplePredicate {
        boolean test(Apple apple);
    }

    // 策略一：选出重的苹果的谓词
    static class AppleHeavyWeightPredicate implements ApplePredicate {
        @Override
        public boolean test(Apple apple) {
            return apple.getWeight() > 150;
        }
    }

    // 策略二：选出绿色苹果的谓词
    static class AppleGreenColorPredicate implements ApplePredicate {
        @Override
        public boolean test(Apple apple) {
            return "green".equals(apple.getColor());
        }
    }

    // 方法引进算法簇
    // 方法执行的结果取决于传入的具体策略，将策略(行为)作为了参数
    private static List<Apple> filterApples(List<Apple> inventory, ApplePredicate predicate) {
        List<Apple> result = new ArrayList<>();
        for (Apple apple : inventory)
            if (predicate.test(apple))
                result.add(apple);
        return result;
    }

    // 运行
    private static void main() {
        List<Apple> inventory = new ArrayList<>(); // 有一筐苹果
        List<Apple> result = filterApples(inventory, new AppleGreenColorPredicate()); // 选出绿色的
    }

    // 5、匿名内部类
    // 上面不同的策略，其实核心逻辑很简单，但是模板代码不少；况且用的时候也只会用一种策略，并且实例化一次。
    private static void main2() {
        List<Apple> inventory = new ArrayList<>(); // 有一筐苹果
        List<Apple> result = filterApples(inventory, new ApplePredicate() { // 选出绿色的
            @Override
            public boolean test(Apple apple) {
                return "green".equals(apple.getColor());
            }
        });
    }

    // 6、Lambda
    // 上面用匿名内部类表示仍然有很多模板代码
    private static void main3() {
        List<Apple> inventory = new ArrayList<>(); // 有一筐苹果
        List<Apple> result = filterApples(inventory, param -> "green".equals(param.getColor())); // 选出绿色的
    }

    // 7、如果是香蕉、鸭梨呢？
    // 谓词要用泛型
    interface Predicate<T> {
        boolean test(T t);
    }

    // 过滤方法
    private static <T> List<T> filter(List<T> list, Predicate<T> p) {
        List<T> result = new ArrayList<>();
        for (T e : list)
            if (p.test(e))
                result.add(e);
        return result;
    }

    // 调用
    private static void main4(List<Banana> inventory) { // 有一筐香蕉
        List result = filter(inventory, t -> "green".equals(t.getColor())); // 选出绿色的
        System.out.println(result.size());
    }

    // Lambda 例子1
    private static void lambda1(List<Apple> list) {
        // 匿名内部类（可见，IDEA提示灰色，不提倡）
        list.sort(
                new Comparator<Apple>() {
                    @Override
                    public int compare(Apple o1, Apple o2) {
                        return o1.getWeight() - o2.getWeight();
                    }
                }
        );
        // Lambda（可见，还是灰色，还能优化）
        list.sort(
                (o1, o2) -> o1.getWeight() - o2.getWeight()
        );
        // Comparator 1.8新加的方法
        list.sort(
                Comparator.comparingInt(Apple::getWeight)
        );
    }

    // Lambda 例子2
    private static void lambda2() {
        // 匿名内部类
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.print("Hello ");
                System.out.println("World");
            }
        }).start();
        // Lambda
        new Thread(() -> {
            System.out.print("Hello ");
            System.out.println("World");
        }).start();
    }

    public static void main(String[] args) {
        List<Banana> inventory = new ArrayList<>();
        inventory.add(new Banana("green", 161));
        inventory.add(new Banana("green", 155));
        inventory.add(new Banana("red", 140));
        main4(inventory);
    }
}


